﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DiscoveryLogic.Analytics.BusinessLogic;
using DiscoveryLogic.Analytics.BusinessLogic.Dedups;
using DiscoveryLogic.Analytics.BusinessLogic.Links;
using DiscoveryLogic.Analytics.BusinessLogic.Rules;
using DiscoveryLogic.Analytics.DataObjects;
using DiscoveryLogic.Analytics.DataObjects.Dedup;
using DiscoveryLogic.Analytics.DataObjects.Networks;
using DiscoveryLogic.Analytics.DataObjects.Rules;
using DiscoveryLogic.Common.Utilities;

namespace DiscoveryLogic.Analytics.Modules.Explorers
{
    /// <summary>
    /// Interaction logic for ExploreNetworkAssociation.xaml
    /// </summary>
    public partial class ExploreNetworkAssociation : UserControl
    {
        public delegate void OnNetworkUpdated(Network network);
        public event OnNetworkUpdated NetworkUpdated;

        public delegate void OnStatusChanged(string msg, int pct);
        public event OnStatusChanged StatusChanged;

        private class BgArgs
        {
            private Network _Network;
            /// <summary></summary>
            public Network Network
            {
                get
                {
                    return this._Network;
                }
                set
                {
                    this._Network = value;
                }
            }

            private EntityRelationRule _LinkRule;
            /// <summary></summary>
            public EntityRelationRule LinkRule
            {
                get
                {
                    return this._LinkRule;
                }
                set
                {
                    this._LinkRule = value;
                }
            }

            private List<string> _SrcKeys;
            /// <summary></summary>
            public List<string> SrcKeys
            {
                get
                {
                    return this._SrcKeys;
                }
                set
                {
                    this._SrcKeys = value;
                }
            }
        }
        private BackgroundWorker _BgWorker;

        private Network _Network;
        private RuleType _RuleType;
        private EntityType _TgtEntityType;
        Dictionary<string, EntityRelationRule> rulesByNames = new Dictionary<string, EntityRelationRule>();

        public ExploreNetworkAssociation(
            Network network, RuleType ruleType)
        {
            InitializeComponent();
            this._Network = network;
            this._RuleType = ruleType;
            this._TgtEntityType = EntityType.Grants;
        }

        public ExploreNetworkAssociation(
            Network network, RuleType ruleType, 
            EntityType tgtEntityType)
            :this(network, ruleType)
        {
            this._TgtEntityType = tgtEntityType;
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            this.txtNetworkName.Text = this._Network.NetworkName;
            List<RuleBase> rules = new List<RuleBase>();
            string iconPath = "/images/link.ico";
            List<RuleBase> linkRules = RuleManager.GetRulesByType(this._RuleType, iconPath);
            if (linkRules != null && linkRules.Count > 0)
                rules.AddRange(linkRules);
            this.rulesByNames = new Dictionary<string, EntityRelationRule>();
            if (rules != null && rules.Count > 0)
            {
                foreach (RuleBase rule in rules)
                {
                    this.cboRules.Items.Add(rule.RuleName);
                    if (rule is EntityRelationRule)
                        this.rulesByNames.Add(rule.RuleName, rule as EntityRelationRule);
                }
            }

            this.cboSrcEntity.Items.Clear();
            this.cboTgtEntity.Items.Clear();
            List<EntityType> entityTypes=new List<EntityType>();
            foreach(EntityBase entity in this._Network.Records)
            {
                if(!entityTypes.Contains(entity.EntityType))
                    entityTypes.Add(entity.EntityType);
            }
            foreach(EntityType entityType in entityTypes)
            {
                this.cboSrcEntity.Items.Add(entityType.ToString());
            }

            foreach(EntityType entityType in Enum.GetValues(typeof(EntityType)))
            {
                this.cboTgtEntity.Items.Add(entityType.ToString());
            }
            this.cboTgtEntity.Text = this._TgtEntityType.ToString();

            this.cboSrcEntity.Text = EntityType.Grants.ToString();
            this.cboTgtEntity.Text = this._TgtEntityType.ToString();
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            if (this.Parent is Window)
            {
                ((Window)this.Parent).Close();
            }
        }

        private void btnOK_Click(object sender, RoutedEventArgs e)
        {
            if (this.cboRules.SelectedIndex >= 0 && !string.IsNullOrEmpty(this.txtNetworkName.Text))
            {
                try
                {
                    EntityRelationRule rule = this.rulesByNames[this.cboRules.SelectedItem.ToString()];
                    List<string> srcKeys = new List<string>();
                    foreach(EntityBase entity in this._Network.Records)
                    {
                        if(entity.EntityType==rule.SrcEntityType)
                        {
                            srcKeys.Add(entity.PKValue());
                        }
                    }

                    BgArgs args=new BgArgs();
                    args.LinkRule = rule;
                    args.Network = this._Network;
                    args.SrcKeys = srcKeys;

                    this._BgWorker = new BackgroundWorker();
                    this._BgWorker.WorkerReportsProgress = true;
                    this._BgWorker.WorkerSupportsCancellation = true;
                    this._BgWorker.ProgressChanged += new ProgressChangedEventHandler(bgWorker_StatusChanged);
                    this._BgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
                    this._BgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_Finished);
                    this._BgWorker.RunWorkerAsync(args);

                    if (this.Parent is Window)
                    {
                        ((Window)this.Parent).Close();
                    }
                }
                catch (Exception ex)
                {
                    ExceptionHandler.HandlesException(ex);
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void bgWorker_Finished(object sender, RunWorkerCompletedEventArgs e)
        {
            MyData.ReadAllNetworks();
            if (this.NetworkUpdated != null)
            {
                this._Network = Network.Read(this._Network.NetworkName);
                this.NetworkUpdated(this._Network);
            }
        }

        private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            this._BgWorker.ReportProgress(10, "Linking network to external entities...");

            BgArgs args = e.Argument as BgArgs;
            EntityRelationWorker worker = new EntityRelationWorker(
                        args.LinkRule, args.Network, args.SrcKeys);
            Network network = worker.ReadRelatedData();
            if (NetworkDedupSetting.Exists(network.NetworkName))
            {
                NetworkDedupSetting dedupSetting = NetworkDedupSetting.Read(network.NetworkName);
                NetworkDedupWorker dedupWorker = new NetworkDedupWorker(network, dedupSetting);
                network = dedupWorker.DedupNetwork();
            }
            network.Save();

            this._BgWorker.ReportProgress(0, "Finished.");

        }

        private void bgWorker_StatusChanged(object sender, ProgressChangedEventArgs e)
        {
            if(this.StatusChanged !=null)
            {
                this.StatusChanged(e.UserState.ToString(), e.ProgressPercentage);
            }
        }

        private void cboTgtEntity_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }
    }
}
